package com.websocket.otp;

import javax.crypto.Mac;
import javax.crypto.spec.SecretKeySpec;
import java.nio.ByteBuffer;
import java.security.InvalidKeyException;
import java.security.NoSuchAlgorithmException;
import java.util.Base64;

public class HOTP {

    private static final int DIGITS = 6; // 验证码位数
    private static final int WINDOW = 1; // 允许的时间窗口

    public static String generateHOTP(String secret, long counter) throws NoSuchAlgorithmException, InvalidKeyException {
        byte[] keyBytes = Base64.getDecoder().decode(secret);
        byte[] counterBytes = ByteBuffer.allocate(8).putLong(counter).array();

        SecretKeySpec keySpec = new SecretKeySpec(keyBytes, "HmacSHA1");
        Mac mac = Mac.getInstance("HmacSHA1");
        mac.init(keySpec);
        byte[] hash = mac.doFinal(counterBytes);

        int offset = hash[hash.length - 1] & 0xF;
        int binary = ((hash[offset] & 0x7F) << 24) |
                ((hash[offset + 1] & 0xFF) << 16) |
                ((hash[offset + 2] & 0xFF) << 8) |
                (hash[offset + 3] & 0xFF);
        int otp = binary % (int)Math.pow(10, DIGITS);

        return String.format("%0" + DIGITS + "d", otp);
    }

    public static boolean verifyHOTP(String secret, long counter, String receivedOTP) throws NoSuchAlgorithmException, InvalidKeyException {
        for (int i = -WINDOW; i <= WINDOW; i++) {
            String expectedOTP = generateHOTP(secret, counter + i);
            if (expectedOTP.equals(receivedOTP)) {
                return true;
            }
        }
        return false;
    }

    public static void main(String[] args) throws NoSuchAlgorithmException, InvalidKeyException {
        String secret = "5aiE5YW05Lyf"; // 你的密钥
        long counter = 1; // 初始计数器
        String otp = generateHOTP(secret, counter);
        System.out.println("Generated OTP: " + otp);

        // 模拟接收到的 OTP
        String receivedOTP = "123456"; // 假设收到的 OTP
        boolean isValid = verifyHOTP(secret, counter, receivedOTP);
        System.out.println("OTP is valid: " + isValid);
    }
}
